package com.huitone.smspfm.oldclient.core;

import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ArrayBlockingQueue;

import com.huitone.smspfm.oldclient.logger.ExtLogger;

import com.bin.common.utils.FileUtils;

/**   
* @Title: AbstractXmlParse.java 
* @Package com.unicom.gddw.xmlparse 
* @Description: TODO(用一句话描述该文件做什么) 
* @author ybliang   
* @date 2017年3月8日 下午5:54:19 
* @version V1.0   
*/
public abstract class AbstractXmlParse<T> {

	private ExtLogger logger = ExtLogger.create(AbstractXmlParse.class);
	
	private String regex = null;
	
	private String startTag = null;
	
	private String endTag = null;
	
	private String dirPath = null;
	
	private int poolSize = 1000;
	
	private List<String> subDirs = null;
	
	private Map<String, ArrayBlockingQueue<File>> map = null;
	
	public AbstractXmlParse(int poolSize, String dirPath, String regex, String startTag, String endTag){
		
		if (dirPath == null) {
			throw new RuntimeException("文件路径不能为空!");
		}
		
		subDirs = FileUtils.getSubDirs(dirPath);
		
		Collections.sort(subDirs);
		
		map = new HashMap<>();
		
		for (String path:subDirs) {
			map.put(path, new ArrayBlockingQueue<>(poolSize));
		}
		
		this.regex = regex;
		this.startTag = startTag;
		this.endTag = endTag;
		this.poolSize = poolSize;
		this.dirPath = dirPath;
		
		readFiles();
		
		updateDirsTimer();
		
		startReadFileTimer();
	}
	
	private synchronized void updateDirs() {
		
		List<String> tmp = FileUtils.getSubDirs(dirPath);
		
		for (String path:tmp) {
			if (!subDirs.contains(path)) {
				subDirs.add(path);
			}
		}
		
		Iterator<String> ite = subDirs.iterator();
		while(ite.hasNext()) {
			String path = ite.next();
			if (!tmp.contains(path)) {
				if (map.get(path).isEmpty()) {
					ite.remove();
					map.remove(path);
				}
			}
		}
		
		Collections.sort(subDirs);
	}
	
	private void updateDirsTimer() {
		new Timer().schedule(new TimerTask() {
			
			@Override
			public void run() {
				updateDirs();
			}
		}, 0, 5 * 60 * 1000);
	}
	
	/**
	 * 读取文件定时器
	 */
	private void startReadFileTimer() {
		
		new Timer().schedule(new TimerTask() {
			
			@Override
			public void run() {
				readFiles();
			}
		}, 0, 1000);
	}
	
	/**
	 * 解析文件内容,并返回对象
	 * @param xmlParse
	 * @return
	 */
	public synchronized List<T> readObj(XmlParse<T> xmlParse) {
		return xmlParse.parse(readAFile());
	}
	
	private void readFiles() {
		
		for (int i = 0 ; i < subDirs.size() ; i ++) {
			
			String dirPath = subDirs.get(i);
			
			List<File> files = FileUtils.getFiles(dirPath, regex);
			
			if (files != null) {
				
				ArrayBlockingQueue<File> blockingQueue = map.get(dirPath);
				
				if (blockingQueue == null) {
					blockingQueue = new ArrayBlockingQueue<>(poolSize);
				}
				
				Collections.sort(files);
				
				for (File file:files) {
					
					if (!blockingQueue.contains(file)) {
						
						blockingQueue.offer(file);
					}
				}
			}
		}
	}
	
	/**
	 * 读取文件内容
	 * @return
	 */
	private StringBuffer readAFile() {
		
		StringBuffer buffer = null;
		
		Iterator<Map.Entry<String, ArrayBlockingQueue<File>>> ite = map.entrySet().iterator();
		
		while(ite.hasNext()) {
			
		 	Map.Entry<String, ArrayBlockingQueue<File>> entry = ite.next();
		 	
		 	ArrayBlockingQueue<File> queue = entry.getValue();
		 	
		 	Iterator<File> iterator = queue.iterator();
		 	
		 	if (iterator.hasNext()){ 
				
				File file = queue.iterator().next();
				
				buffer = FileUtils.read(file, "GBK");
				
				// 判断文件是否完整,内容完整的文件才会读取,否则将视为损坏文件处理
				if (isIntact(buffer.toString())) {
					FileUtils.delete(file);
				} else {
					String fileRename = file.getName() + ".bad";
					String parentPath = file.getParent();
					FileUtils.rename(file, fileRename);
					buffer = null;
					logger.warn("文件不完整,没有找到文件开始符号或者结束符号,文件名称:" + parentPath + File.separator + fileRename);
				}
				
				queue.poll();
				
				break;
			}
		}
		
		return buffer;
	}
	
	/**
	 * 判断文件内容是否完整(是否有开始符/结束符)
	 * @param content
	 * @return
	 */
	private boolean isIntact(String content) {
		
		boolean result = false;
		
		if (content != null) {
			
			boolean hasStartTag = false;
			boolean hasEndTag = false;
			
			if (content.startsWith(startTag)) {
				hasStartTag = true;
			}
			
			if (content.endsWith(endTag)) {
				hasEndTag = true;
			}
			
			if (hasStartTag && hasEndTag) {
				result = true;
			}
		}
		return result;
	}
	
	public interface XmlParse<T> {
		List<T> parse(StringBuffer buffer);
	}
}
